#include "connectiondialog.h"
#include <QRegExp>
#include <thread>
#include <QDebug>
#include <QFile>
#include <QFileInfo>

ConnectionDialog::ConnectionDialog(QWidget *parent) : QDialog(parent) {
    // 创建IP和端口号的输入框
    ipLineEdit = new QLineEdit(this);
    portLineEdit = new QLineEdit(this);

    // 创建连接和断开连接的按钮
    connectButton = new QPushButton("连接", this);
    disconnectButton = new QPushButton("断开连接", this);
    disconnectButton->setEnabled(false); // 默认断开连接按钮不可用

    // 设置布局
    QVBoxLayout *layout = new QVBoxLayout(this);
    layout->addWidget(new QLabel("IP地址:"));
    layout->addWidget(ipLineEdit);
    layout->addWidget(new QLabel("端口号:"));
    layout->addWidget(portLineEdit);
    layout->addWidget(connectButton);
    layout->addWidget(disconnectButton);

    client_socket = new QTcpSocket(this);

    // 连接按钮的信号与槽
    connect(connectButton, &QPushButton::clicked, this, &ConnectionDialog::onConnectClicked);
    connect(disconnectButton, &QPushButton::clicked, this, &ConnectionDialog::onDisconnectClicked);
}

ConnectionDialog::~ConnectionDialog()
{

}

bool ConnectionDialog::isValidIPv4(const QString &ip)
{
    QRegExp regExp("^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$");
    return regExp.exactMatch(ip);
}

void ConnectionDialog::server_connect()
{
    QString ip = ipLineEdit->text();
    quint16 port = portLineEdit->text().toUShort();

    if (isValidIPv4(ip)) {
        //ip地址有效
        emit setLogs("ip 地址有效");
    }
    else {
        //ip地址无效
        emit setLogs("ip 地址无效");
        qDebug()<<"ip无效";
        return;
    }

    // 连接到服务器
    client_socket->connectToHost(ip, port);

    if (client_socket->waitForConnected(3000)) {
        //连接成功，则启用断开连接按钮，禁用连接按钮
        disconnectButton->setEnabled(true);
        connectButton->setEnabled(false);
        ipLineEdit->setEnabled(false);
        portLineEdit->setEnabled(false);
        emit setLogs("连接服务端成功");
        qDebug()<<"连接服务端成功";
    }
    else {
        //连接失败
        emit setLogs("连接服务端失败");
        qDebug()<<"连接服务端失败";
    }
}
void ConnectionDialog::onConnectClicked() {
    std::thread camera_thread(&ConnectionDialog::server_connect,this);
    qDebug()<<"create thread";
    camera_thread.detach();
}

void ConnectionDialog::onDisconnectClicked() {
    if (client_socket) {
        client_socket->close();
        delete client_socket;
        client_socket = nullptr;
        disconnectButton->setEnabled(false);
        connectButton->setEnabled(true);
        ipLineEdit->setEnabled(true);
        portLineEdit->setEnabled(true);
        emit setLogs("断开服务端成功");
    }
}

void ConnectionDialog::upload_thread(QString file) {
    qDebug()<<"thread start\n";
    cmd_t wr_cmd;
    ack_t wr_ack;
    int pkid = 0;
    int pk_size = 512;
    int file_size;

    if (client_socket->isOpen()) {
        qDebug()<<"socket open\n";
    }
    else {
        qDebug()<<"socket not open\n";
        emit setLogs("未连接服务端");
        return;
    }

    // 打开文件
    QFile qfile(file);
    if (!qfile.open(QIODevice::ReadOnly)) {
        emit setLogs("打开文件失败，上传中断");
        return;
    }
    file_size = qfile.size();

    QFileInfo fileInfo(qfile);
    wr_cmd.command = write;
    memcpy(wr_cmd.cmd.write_cmd.filename, fileInfo.fileName().toUtf8().constData(),
           sizeof(wr_cmd.cmd.write_cmd.filename));
    qDebug()<<"send file:"<<wr_cmd.cmd.write_cmd.filename;


    // 读取并发送文件内容xiabn
    while (!qfile.atEnd()) {

        if (file_size >= 512) {
            pk_size = 512;
            file_size -= 512;
        }
        else {
            pk_size = file_size;
        }

        wr_cmd.packet_id = pkid;
        wr_cmd.data_size = pk_size;
        // 创建一个QByteArray用于存储序列化后的数据
        QByteArray byteArray;
        // 创建一个QDataStream用于写入数据到byteArray
        QDataStream dataStream(&byteArray, QIODevice::WriteOnly);

        // 设置数据流的版本，以确保兼容性
        dataStream.setVersion(QDataStream::Qt_5_0);

        // 将结构体数据写入数据流
        dataStream << wr_cmd.command << wr_cmd.packet_id << wr_cmd.data_size;

        // 为了写入固定大小的filename，我们可以创建一个QByteArray，填充到32字节
        QByteArray fixedSizeFilename(wr_cmd.cmd.write_cmd.filename, 32); // 从wr_cmd.filename复制32字节到QByteArray
        dataStream.writeRawData(fixedSizeFilename.constData(), 32); // 写入32字节

        QByteArray buffer = qfile.read(pk_size);
        byteArray = byteArray + buffer;
        qDebug()<<"send bytes:"<<byteArray.size();
        if (client_socket->write(byteArray) == -1) {
            emit setLogs("上传数据包失败");
            qfile.close();
            return;
        }
        // 等待数据被发送出去
        client_socket->waitForBytesWritten();

        // 等待数据，设置超时为3000毫秒（3秒）
        if (client_socket->waitForReadyRead(3000)) {
            // 如果在3秒内有数据可读，读取数据
            QByteArray ack_data = client_socket->readAll();
            qDebug() << "Received ack, size:"<<ack_data.size();
            memcpy(&wr_ack, ack_data.data(), ack_data.size());
            if (wr_ack.packet_id != pkid || wr_ack.cmd_ack != write) {
                emit setLogs("ack id or cmd error");
                qfile.close();
                return;
            }

            QString ack_filename = QString::fromUtf8(wr_ack.ack.write_ack.filename);
            if (fileInfo.fileName() != ack_filename) {
                emit setLogs("ack filename error");
                qfile.close();
                return;
            }

            switch (wr_ack.flag) {
            case noerror:
            {
                break;
            }
            case error:
            {
                emit setLogs("ack  error");
                qfile.close();
                return;
            }
            case busy:
            {
                emit setLogs("busy");
                qfile.close();
                return;
            }
            default:
            {
                emit setLogs("flag uknow");
                qfile.close();
                return;
            }
            }
        } else {
            // 如果3秒内没有数据可读，则报超时
            qDebug() << "No data received within 3 seconds, timeout!";
            emit setLogs("服务器回复超时");
            qfile.close();
            return;
        }
        pkid++;
    }

    // 文件发送完毕，关闭文件
    emit setLogs("上传完成");
    qfile.close();
    return;
}

void ConnectionDialog::upload_slot(const QString &file) {
    qDebug()<<"upload slot\n";

    QString temp(file);
    std::thread th(&ConnectionDialog::upload_thread, this, temp);
    th.detach();

    // 使用 lambda 表达式
    //    std::thread th([&]() {
    //        this->upload_thread(file);
    //    });
}


void ConnectionDialog::splitStringIntoList(QList<QString>& stringList, const char* charArray, int num)
{
    QString currentString;

    if (charArray == nullptr) {
        return; // 返回空的QList，如果传入的数组是空指针
    }

    while (num) { // 遍历char数组直到遇到空字符
        if (*charArray == '\n') {
            if (!currentString.isEmpty()) {
                stringList.append(currentString); // 将当前字符串添加到列表中
                currentString.clear(); // 清空当前字符串，为下一个字符串做准备
                num --;
            }
        } else {
            currentString.append(*charArray); // 将字符添加到当前字符串
        }
        ++charArray; // 移动到下一个字符
    }

    // 检查最后一个字符串（如果最后一个字符不是'\n'）
    if (!currentString.isEmpty()) {
        stringList.append(currentString);
    }

    return;
}

void ConnectionDialog::refresh_server()
{
    qDebug()<<"refresh";
    cmd_t refresh_cmd;
    ack_t refresh_ack;
    int pkid = 0;
    int server_file_num;
    QList<QString> server_filename;

    if (client_socket->isOpen()) {
        qDebug()<<"socket open\n";
    }
    else {
        qDebug()<<"socket not open\n";
        emit setLogs("未连接服务端");
        return;
    }

    refresh_cmd.command = enum_file;
    refresh_cmd.packet_id = pkid;
    refresh_cmd.data_size = 12;

    while (1) {
        QByteArray byteArray;
        // 创建一个QDataStream用于写入数据到byteArray
        QDataStream dataStream(&byteArray, QIODevice::WriteOnly);

        // 设置数据流的版本，以确保兼容性
        dataStream.setVersion(QDataStream::Qt_5_0);

        // 将结构体数据写入数据流
        dataStream << refresh_cmd.command << refresh_cmd.packet_id << refresh_cmd.data_size;

        if (client_socket->write(byteArray) == -1) {
            emit setLogs("枚举文件失败");
            return;
        }
        // 等待数据被发送出去
        client_socket->waitForBytesWritten();

        // 等待数据，设置超时为3000毫秒（3秒）
        if (client_socket->waitForReadyRead(6000)) {
            // 如果在3秒内有数据可读，读取数据
            QByteArray ack_data = client_socket->readAll();
            qDebug() << "Received ack, size:"<<ack_data.size();
            memcpy(&refresh_ack, ack_data.data(), ack_data.size());
            if (refresh_ack.packet_id != pkid || refresh_ack.cmd_ack != enum_file) {
                emit setLogs("ack id or cmd error");
                return;
            }

            server_file_num = refresh_ack.ack.enum_file_ack.file_num;
            qDebug()<<"server file num "<<server_file_num;
            splitStringIntoList(server_filename,
                                (const char *)&refresh_ack.ack.enum_file_ack.data,
                                server_file_num);
            qDebug()<<"file num "<<server_filename.size();
            for (int i = 0; i < server_filename.size(); i++) {
                qDebug()<<"file name: "<<server_filename[i];
            }
            if (refresh_ack.flag != continue_enum) {
                break;
            }
        }
        else {
            emit setLogs("枚举回复超时");
            return;
        }
    }
    emit enum_down(server_filename, server_file_num);
    emit setLogs("枚举完成");

}

void ConnectionDialog::refresh_slot()
{
    std::thread th(&ConnectionDialog::refresh_server, this);
    th.detach();
}

void ConnectionDialog::delete_file_thread(QString file) {
    qDebug()<<"start delete "<<file;
    cmd_t delete_cmd;
    ack_t delete_ack;
    int pkid = 0;

    if (client_socket->isOpen()) {
        qDebug()<<"socket open\n";
    }
    else {
        qDebug()<<"socket not open\n";
        emit setLogs("未连接服务端");
        return;
    }

    delete_cmd.command = delete_file;
    delete_cmd.packet_id = pkid;
    delete_cmd.data_size = 12+32;
    //memcpy(delete_cmd.cmd.delete_cmd.filename, &file, 32);

    QByteArray byteArray;
    // 创建一个QDataStream用于写入数据到byteArray
    QDataStream dataStream(&byteArray, QIODevice::WriteOnly);

    // 设置数据流的版本，以确保兼容性
    dataStream.setVersion(QDataStream::Qt_5_0);

    // 将结构体数据写入数据流
    dataStream << delete_cmd.command << delete_cmd.packet_id << delete_cmd.data_size;

    byteArray.append(file.toUtf8());
    if (file.toUtf8().size() < 32) {
        byteArray.append(QByteArray(32 - file.toUtf8().size(), '\0'));
    }

    if (client_socket->write(byteArray) == -1) {
        emit setLogs("删除文件失败");
        return;
    }
    // 等待数据被发送出去
    client_socket->waitForBytesWritten();

    // 等待数据，设置超时为3000毫秒（3秒）
    if (client_socket->waitForReadyRead(3000)) {
        // 如果在3秒内有数据可读，读取数据
        QByteArray ack_data = client_socket->readAll();
        qDebug() << "Received ack, size:"<<ack_data.size();
        memcpy(&delete_ack, ack_data.data(), ack_data.size());
        if (delete_ack.packet_id != pkid || delete_ack.cmd_ack != delete_file) {
            emit setLogs("ack id or cmd error");
            return;
        }
        switch (delete_ack.flag) {
        case noerror:
        {
            emit setLogs("删除文件成功");
            break;
        }
        case error:
        {
            emit setLogs("ack  error");
            return;
        }
        case busy:
        {
            emit setLogs("busy");
            return;
        }
        case nofile:
        {
            emit setLogs("没有这个文件");
            return;
        }
        default:
        {
            emit setLogs("flag uknow");
            return;
        }
        }
    }
    else {
        emit setLogs("枚举回复超时");
        return;
    }
}

void ConnectionDialog::delete_cmd_slot(QString file)
{
    std::thread th(&ConnectionDialog::delete_file_thread, this, file);
    th.detach();
}


void ConnectionDialog::download_file_thread(QString file)
{
    qDebug()<<"start download "<<file;
    cmd_t read_cmd;
    ack_t read_ack;
    int pkid = 0;
    int start_index = 0;
    int bytesWritten;

    if (client_socket->isOpen()) {
        qDebug()<<"socket open\n";
    }
    else {
        qDebug()<<"socket not open\n";
        emit setLogs("未连接服务端");
        return;
    }
    read_cmd.command = read;
    read_cmd.data_size = 12+40;
    read_cmd.cmd.read_cmd.size = 512;
    memcpy(read_cmd.cmd.read_cmd.filename, file.toStdString().c_str(), 32);

    QFile local_file("./database/"+file);
    // 打开文件用于写入，如果文件不存在将会被创建
    if (!local_file.open(QIODevice::WriteOnly)) {
        qDebug() << "无法打开文件进行写入";
        return;
    }


    while(1) {
        read_cmd.packet_id = pkid;
        read_cmd.cmd.read_cmd.start = start_index;

        QByteArray byteArray;
        // 创建一个QDataStream用于写入数据到byteArray
        QDataStream dataStream(&byteArray, QIODevice::WriteOnly);

        // 设置数据流的版本，以确保兼容性
        dataStream.setVersion(QDataStream::Qt_5_0);

        // 将结构体数据写入数据流
        dataStream << read_cmd.command << read_cmd.packet_id << read_cmd.data_size;

        dataStream << read_cmd.cmd.read_cmd.start << read_cmd.cmd.read_cmd.size;

        byteArray.append(file.toUtf8());
        if (file.toUtf8().size() < 32) {
            byteArray.append(QByteArray(32 - file.toUtf8().size(), '\0'));
        }

        if (client_socket->write(byteArray) == -1) {
            emit setLogs("删除文件失败");
            return;
        }
        // 等待数据被发送出去
        client_socket->waitForBytesWritten();

        // 等待数据，设置超时为3000毫秒（3秒）
        if (client_socket->waitForReadyRead(3000)) {
            // 如果在3秒内有数据可读，读取数据
            QByteArray ack_data = client_socket->readAll();
            qDebug() << "Received ack, size:"<<ack_data.size();
            memcpy(&read_ack, ack_data.data(), ack_data.size());
            if (read_ack.packet_id != pkid || read_ack.cmd_ack != read) {
                emit setLogs("ack id or cmd error");
                return;
            }

            QString ack_filename = QString::fromUtf8(read_ack.ack.read_ack.filename);
            if (ack_filename != file) {
                emit setLogs("ack filename error");
                return;
            }

            if(read_ack.ack.read_ack.read_size > 0) {
                bytesWritten = local_file.write(read_ack.ack.read_ack.data, read_ack.ack.read_ack.read_size);
                if (bytesWritten == -1) {
                    emit setLogs("写入文件时发生错误");
                    return;
                } else if (bytesWritten != read_ack.ack.read_ack.read_size) {
                    qDebug() << "只写入了部分数据";
                } else {
                    qDebug() << "数据成功写入文件";
                }
                start_index += read_ack.ack.read_ack.read_size;
            }

            switch (read_ack.flag) {
            case noerror:
            {
                emit setLogs("no error");
                return;;
            }
            case error:
            {
                emit setLogs("ack error");
                return;
            }
            case busy:
            {
                emit setLogs("busy");
                return;
            }
            case nofile:
            {
                emit setLogs("no file");
                return;
            }
            case continue_read:
            {
                emit setLogs("文件下载中");
                break;
            }
            case read_done:
            {
                local_file.close();
                emit setLogs("文件下载完成");
                return;
            }
            default:
            {
                emit setLogs("flag uknow");
                return;
            }
            }
        } else {
            // 如果3秒内没有数据可读，则报超时
            qDebug() << "No data received within 3 seconds, timeout!";
            emit setLogs("服务器回复超时");
            return;
        }
        pkid++;
    }

}


void ConnectionDialog::download_file_slot(QString file)
{
    std::thread th(&ConnectionDialog::download_file_thread, this, file);
    th.detach();
}


